package com.springcloud.controller;

import com.alibaba.fastjson.JSONObject;
import com.springcloud.model.User;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 服务消费者可以返回JSON或视图页面
 * 我们使用@RestController仅仅是方便测试
 */
@RestController
public class ConsumerController {

    @Resource
    private RestTemplate restTemplate;

    @RequestMapping("/test")
    public Object test(){
        String url="http://localhost:8081/test";
        /**
         * getForEntity 使用Http协议已Get方式提交请求,访问远程服务,对应服务提供者的@RequestMapping或@GetMapping
         * 参数 1 为请求的具体地址路径
         * 参数 2 为本次请求的响应数据封装类型
         *       如果远程服务返回的是基本数据格式(包括基本数据类型或字符串),我们可以使用对应基本类型包装类或String类封装响应数据(推荐使用String)
         *       如果远程服务返回的是JSON对象格式的字符串数据,我们可以使用String封装数据然后利用Json工具转换成对应的Java对象(例如FastJSON)
         *       也可以使用Map集合或实体类来封装响应数据
         *       如果远程服务返回的是JSON对象数组格式的字符串数据,我们可以使用String封装数据然后利用Json工具转换成对应的Java对象(例如FastJSON
         *       也可使用使用List或Set集合封装响应数据
         * 返回值类型:
         *   返回一个ResponseEntity对象,这个对象用于封装响应所有内容,包括响应头 响应状态码 响应体(具体的响应数据)
         *  注意:
         *    返回值ResponseEntity可以指定一个泛型,用于存放响应的具体数据的,具体类型要参考getForEntity方法的参数2
         */
        ResponseEntity<String> responseEntity= restTemplate.getForEntity(url,String.class);
        System.out.println(responseEntity.getStatusCode());
        System.out.println(responseEntity.getStatusCodeValue());
        System.out.println(responseEntity.getHeaders());
        String body=responseEntity.getBody();
        return "服务消费者-----"+body;
    }

    @RequestMapping("/getUser01")
    public Object getUser01(){
        String url="http://localhost:8081/getUser";

        ResponseEntity<String> responseEntity= restTemplate.getForEntity(url,String.class);
        String body=responseEntity.getBody();
        //利用FastJson的工具类将一个Json对象格式的字符串数据转换成Java的某个实体类
        User user=JSONObject.parseObject(body, User.class);
        return "服务消费者----- name:"+user.getName()+" age:"+user.getAge();
    }
    @RequestMapping("/getUser02")
    public Object getUser02(){
        String url="http://localhost:8081/getUser";
        ResponseEntity<Map> responseEntity= restTemplate.getForEntity(url,Map.class);
        Map body=responseEntity.getBody();
        return "服务消费者----- name:"+body.get("name")+"  age:"+body.get("age");
    }
    @RequestMapping("/getUser03")
    public Object getUser03(){
        String url="http://localhost:8081/getUser";
        ResponseEntity<User> responseEntity= restTemplate.getForEntity(url,User.class);
        User body=responseEntity.getBody();
        return "服务消费者----- name:"+body.getName()+"  age:"+body.getAge();
    }

    @RequestMapping("/getUserList")
    public Object getUserList(){
        String url="http://localhost:8081/getUserList";
        //注意:由于getForEntity方法的参数2使用List或Set接收数据不能指定泛型类型,因此Spring会使用LinkedHashMap
        //封装List或Set中的每个元素
        ResponseEntity<List> responseEntity= restTemplate.getForEntity(url,List.class);
        List list=responseEntity.getBody();
        list.forEach(obj-> System.out.println(obj.getClass()));
        return "服务消费者----- "+list;
    }

    @RequestMapping("/params01")
    public Object params01(){
        //使用字符串拼接方式传递参数操作简单,但是参数多时代码阅读性比较低
        String url=String.format("http://localhost:8081/params?name=%s&age=%s","王五1",25);
        ResponseEntity<User> responseEntity= restTemplate.getForEntity(url,User.class);
        return "服务消费者----- "+responseEntity.getBody();
    }
    @RequestMapping("/params02")
    public Object params02(){
        //使用字符串拼接方式传递参数操作简单,但是参数多时代码阅读性比较低
        String url="http://localhost:8081/params?name={0}&age={1}";
        /**
         * getForEntity 方法参数3 为本次请求地址路径的动态数据,取值为Object类型的可变长度参数或一个Map集合
         * 注意:
         *   地址路径中的{0}和{1}为地址路径中的占位符,需要后期动态赋值,其中{0}和{1}中的0和1需要参数3
         *   这个Object类型的可变长度参数的索引一一对应
         */
        ResponseEntity<User> responseEntity= restTemplate.getForEntity(url,User.class,"王五2",25);
        return "服务消费者----- "+responseEntity.getBody();
    }
    @RequestMapping("/params03")
    public Object params03(){
        //使用字符串拼接方式传递参数操作简单,但是参数多时代码阅读性比较低
        String url="http://localhost:8081/params?name={name}&age={age}";
        /**
         * getForEntity 方法参数3 为本次请求地址路径的动态数据,取值为Object类型的可变长度参数或一个Map集合
         * 注意:
         *   地址路径中的{name}和{age}为地址路径中的占位符,需要后期动态赋值,其中{name}和{age}中的name和age需要参数3
         *   这个Map集合的key一一对应
         */
        Map params=new HashMap();
        params.put("name","王五3");
        params.put("age",25);
        ResponseEntity<User> responseEntity= restTemplate.getForEntity(url,User.class,params);
        return "服务消费者----- "+responseEntity.getBody();
    }

    @RequestMapping("/getForObjectTest")
    public Object getForObjectTest(){
        //使用字符串拼接方式传递参数操作简单,但是参数多时代码阅读性比较低
        String url="http://localhost:8081/getUser";
        /**
         * getForObject 作用于使用方法与getForEntity方法基本一致,区别在于返回值类型
         *  getForObject返回的是具体的数据类型封装对象不是ResponseEntity因此不能获取
         *  响应的头以及响应状态码.在不需要响应头或响应状态时建议使用getForObject
         *  具体返回类型取决于getForObject方法的参数2
         */
        User user= restTemplate.getForObject(url,User.class);
        return "服务消费者----- "+user;
    }

    @RequestMapping("/postTest")
    public Object postTest(){
        String url="http://localhost:8081/postTest";
        /**
         * Post相关方法与Get相关方法使用方式类似,它使用使用Http协议已Post方式提交请求访问远程服务
         * 对应服务提供者的@RequestMapping以及@PostMapping
         *  参数 1 为请求地址路径
         *  参数 2 为请求体封装对象(Post请求时的请求参数)
         *  参数 3 为本次响应的数据封装对象
         *  参数 4 为地址路径动态数据
         *  注意:
         *    1.参数2取值为Map集合要求这个Map的value泛型必须是List或使用Map集合的子类LinkedMultiValueMap,这个类是Spring
         *    提供的,它的value泛型就是List
         *    2.Post主要针对数据添加,速度比Get请求要慢,但是可以传递的数据量理论没有上限,通常建议使用Get相关方法替代除非
         *    远程服务明确使用了@PostMapping
         */
        LinkedMultiValueMap params=new LinkedMultiValueMap();
        /**
         * 向Map集合中添加数据,如果key为name在Map集合中存在,则将数据 赵六 设置到 key为name所对应的List集合的尾部
         * 如果key为name在Map集合中不存在则创建一个List集合然后将数据 赵六 设置到这个List集合中,然后在将List设置到
         * Map集合中key为name
         */
        params.add("name","赵六");
        params.add("age",26);
        User user= restTemplate.postForObject(url,params,User.class);
        return "服务消费者----- "+user;
    }

    @RequestMapping("/putTest")
    public Object putTest(){
        String url="http://localhost:8081/putTest";
        /**
         * Put相关方法  使用使用Http协议已Put方式提交请求访问远程服务 对应服务提供者的@PutMapping
         *  参数 1 为请求地址路径
         *  参数 2 为请求体封装对象(Post请求时的请求参数)
         *  参数 3 为地址路径动态数据
         *  注意:
         *    1.Put相关方法主要针对数据的修改,这个方法没有返回值类型因此我们不知道本次请求是否修改成功
         *    所以不推荐使用,除非服务提供者明确使用了@PutMapping
         */
        LinkedMultiValueMap params=new LinkedMultiValueMap();

        params.add("name","陈七");
        params.add("age",27);
        restTemplate.put(url,params);
        return "服务消费者----- ";
    }

    @RequestMapping("/deleteTest")
    public Object deleteTest(){
        String url="http://localhost:8081/deleteTest?id={0}";
        /**
         * Delete相关方法  使用使用Http协议已Delete方式提交请求访问远程服务 对应服务提供者的@DeleteMapping
         *  参数 1 为请求地址路径
         *  参数 2 为地址路径动态数据
         *  注意:
         *    1.Delete相关方法主要针对数据的删除,对应服务提供者的DeleteMapping,没有返回值类型所无法获取本次删除
         *    操作是否成功,因此不推荐使用除非服务提供者明确使用@DeleteMapping
         */
        restTemplate.delete(url,100);
        return "服务消费者----- ";
    }
}
